<?php
namespace App\Http\Controllers\Payment;

use App\Http\Controllers\Controller;
use App\Jobs\PushMsgJob;
use App\Jobs\SendSystemMsgJob;
use App\Libraries\Decorator\Balance\BalanceDecorator;
use App\Libraries\Decorator\Tool\IsEndDecorator;
use App\Libraries\Tools\CheckAuth;
use App\Libraries\Tools\ConstVar;
use App\Libraries\Tools\Msg;
use App\Libraries\Tools\Tools;
use App\Models\HongBao\HongBao;
use App\Models\Order\Order;
use App\Models\Post\Post;
use App\Models\Post\PostPurchase;
use App\Models\Product\Product;
use App\Models\Product\ProductPurchase;
use App\Models\Shop\Shop;
use App\Models\Shop\ShopCoupon;
use App\Models\Shop\ShopCouponPurchase;
use App\Models\Shop\ShopManager;
use App\Models\User\Address;
use App\Models\User\Balance;
use App\Models\User\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;


class BalanceController extends Controller
{

    protected $post;
    protected $postPurchase;
    protected $auth_user;
    protected $address;
    protected $product;
    protected $productPurchase;
    protected $user;
    protected $balance;
	protected $shopCoupon;
	protected $shopCouponPurchase;
    protected $hongBao;
    protected $order;

    public function __construct(Post $post, User $user,
								ShopCoupon $shopCoupon, ShopCouponPurchase $shopCouponPurchase,
                                PostPurchase $postPurchase, Address $address,
                                Product $product, ProductPurchase $productPurchase,
                                Balance $balance, HongBao $hongBao, Order $order){
        $this->post = $post;
        $this->postPurchase = $postPurchase;
        $this->auth_user = Auth::user();
        $this->address = $address;
        $this->product = $product;
        $this->productPurchase = $productPurchase;
        $this->user = $user;
        $this->balance = $balance;
        $this->shopCoupon = $shopCoupon;
        $this->shopCouponPurchase = $shopCouponPurchase;
        $this->hongBao = $hongBao;
        $this->order = $order;
    }

    public function balance(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'id' => 'required|integer',
            'type' => 'required|in:1,2,3,4,5,6',//1-post 2-product 3-transfer_to_shop 4-coupon 5-transfer_to_user 6-hongbao
            'address_id' => 'integer',
            'quantity' => 'integer',
            'hong_bao_id' => 'integer',
            'transfer_amount' => 'numeric|required_if:type,3,5,6',
            'password' => 'string|size:6',
        ], [
            'id.required' => '10001',
            'id.integer' => '10002',
            'type.required' => '10001',
            'type.in' => '10002',
            'address_id.integer' => '10002',
            'quantity.integer' => '10002',
            'hong_bao_id.integer' => '10002',
            'transfer_amount.numeric' => '10002',
            'transfer_amount.required_if' => '10001',
            'password.string' => '10002',
            'password.size' => '10002',
        ]);

        if ($validator->fails()) {
            return $this->sendFailResponse(400, $validator->errors()->first());
        }

        if(!empty($request['password'])){
            $err_code = CheckAuth::checkPaymentPw(Auth::user(), $request['password']);
            if($err_code != 200){
                return $this->sendFailResponse(400, $err_code);
            }
        }

        switch($request['type']){//1-post 2-product 3-transfer_to_shop 4-coupon 5-transfer_to_user 6-hongbao
            case ConstVar::$ORDER_TYPE_POST:
                $model = $this->post;
                $model_ext = $this->postPurchase;
                break;
            case ConstVar::$ORDER_TYPE_PRODUCT:
                $model = $this->product;
                $model_ext = $this->address;
                break;
            case ConstVar::$ORDER_TYPE_TRANSFER_TO_SHOP:
                $model = new User();
                $model_ext = new Shop();
                break;
            case ConstVar::$ORDER_TYPE_COUPON:
                $model = $this->shopCoupon;
                $model_ext = $this->hongBao;
                break;
            case ConstVar::$ORDER_TYPE_TRANSFER_TO_USER:
                $model = new User();
                $model_ext = null;
                break;
            default:
                return $this->sendFailResponse(400, 50001);
        }
        DB::beginTransaction();
        try{
            $rs = $this->order->logic($request, $this->auth_user, ConstVar::$ORDER_CHANNEL_BALANCE, $model, $model_ext);
            if($rs['code'] != 200){
                return $this->sendFailResponse(400, $rs['code']);
            }
            $real_amount = $rs['data']['price']-$rs['data']['hong_bao_amount'];
            $order_info = explode('_', $rs['data']['out_trade_no']);
            switch($request['type']){//1-post 2-product 3-transfer 4-coupon
                case ConstVar::$ORDER_TYPE_POST:
                    $postPurchase = $this->postPurchase->where('order_id',$order_info[0])->first();
                    $postPurchase->status=1;
                    $postPurchase->save();
                    $purchase_id = $postPurchase->id;
                    $balance_id = $this->balance->add(//收益记录
                        Msg::balance_consumption().'_'.Msg::balance_post_profit($request['id']),
                        $this->auth_user->user_id,
                        $rs['data']['ext_id'],//作者ID
                        ConstVar::$BALANCE_CHANNEL_BALANCE,
                        ConstVar::$BALANCE_CHANNEL_BALANCE,
                        ConstVar::$ORDER_TYPE_POST,
                        $request['id'],
                        $real_amount,
                        $purchase_id,
                        $rs['data']['hong_bao_id'],
                        $rs['data']['hong_bao_amount']
                    );
//                    $this->user->where('user_id', $rs['data']['ext_id'])->increment('balance', $rs['data']['price']);
                    break;
                case ConstVar::$ORDER_TYPE_PRODUCT:
                    $productPurchase = $this->productPurchase->where('order_id',$order_info[0])->first();
                    $productPurchase->status=1;
                    $productPurchase->save();
                    $purchase_id = $productPurchase->id;
                    $balance_id = $this->balance->add(//消费记录
                        Msg::balance_consumption().'_'.Msg::balance_product_profit($request['id']),
                        $this->auth_user->user_id,
                        0,
                        ConstVar::$BALANCE_CHANNEL_BALANCE,
                        ConstVar::$BALANCE_CHANNEL_BALANCE,
                        ConstVar::$ORDER_TYPE_PRODUCT,
                        $request['id'],
                        $real_amount,
                        $purchase_id,
                        $rs['data']['hong_bao_id'],
                        $rs['data']['hong_bao_amount'],
                        ConstVar::$BALANCE_STATUS_SUCCESS,
                        ConstVar::$BALANCE_TYPE_USER,
                        ConstVar::$BALANCE_TYPE_SYSTEM
                    );
                    $product = Product::find($productPurchase->product_id);
                    if($product->category == 2){
//                              todo      dispatch(new MLMJob($user_id, $channel, $product_id, $this->id));
                        (new User)->addVIP($this->auth_user->user_id, $product->level, $product->validity);
                    }
                    break;
                case ConstVar::$ORDER_TYPE_TRANSFER_TO_SHOP:
                    Shop::where('shop_id', $order_info[2])->increment('balance', $this->order->total_amount);
                    $owner = ShopManager::where('shop_id', $order_info[2])
                        ->where('status', 1)->where('level', 1)->first();
                    $balance_id = $this->balance->add(//transfer记录
                        Msg::balance_consumption().'_'.Msg::balance_transfer_profit(),
                        $this->order->user_id,
                        $order_info[2],
                        ConstVar::$BALANCE_CHANNEL_BALANCE,
                        ConstVar::$BALANCE_CHANNEL_BALANCE,
                        ConstVar::$ORDER_TYPE_TRANSFER_TO_SHOP,
                        $order_info[2],
                        $this->order->total_amount,
                        0,
                        $this->order->hong_bao_id,
                        $this->order->hong_bao_amount,
                        ConstVar::$BALANCE_STATUS_SUCCESS,
                        ConstVar::$BALANCE_TYPE_USER,
                        ConstVar::$BALANCE_TYPE_SHOP
                    );
                    if(!empty($owner)){
                        dispatch(new SendSystemMsgJob([$owner->user_id], Msg::transfer_to_shop($this->order->total_amount), 0));
                        dispatch(new PushMsgJob([$owner->user_id], Msg::transfer_to_shop($this->order->total_amount), 0));
                    }
                    break;
				case ConstVar::$ORDER_TYPE_COUPON:
                    $shopCouponPurchase = $this->shopCouponPurchase->where('order_id',$order_info[0])->first();
                    $shopCouponPurchase->status=0;
                    $shopCouponPurchase->save();
                    $purchase_id = $shopCouponPurchase->id;
                    $balance_id = $this->balance->add(//消费记录
						Msg::balance_consumption().'_'.Msg::balance_coupon_profit($request['id']),
						$this->auth_user->user_id,
                        0,
                        ConstVar::$BALANCE_CHANNEL_BALANCE,
                        ConstVar::$BALANCE_CHANNEL_BALANCE,
						ConstVar::$ORDER_TYPE_COUPON,
						$request['id'],
                        $real_amount,
                        $purchase_id,
                        $rs['data']['hong_bao_id'],
                        $rs['data']['hong_bao_amount'],
                        ConstVar::$BALANCE_STATUS_SUCCESS,
                        ConstVar::$BALANCE_TYPE_USER,
                        ConstVar::$BALANCE_TYPE_SYSTEM
					);
					break;
                case ConstVar::$ORDER_TYPE_TRANSFER_TO_USER:
                    User::where('user_id', $order_info[2])->increment('balance', $this->order->total_amount);
                    $balance_id = $this->balance->add(//transfer记录
                        Msg::balance_consumption().'_'.Msg::balance_transfer_profit(),
                        $this->order->user_id,
                        $order_info[2],
                        ConstVar::$BALANCE_CHANNEL_BALANCE,
                        ConstVar::$BALANCE_CHANNEL_BALANCE,
                        ConstVar::$ORDER_TYPE_TRANSFER_TO_USER,
                        $order_info[2],
                        $this->order->total_amount,
                        0,
                        $this->order->hong_bao_id,
                        $this->order->hong_bao_amount,
                        ConstVar::$BALANCE_STATUS_SUCCESS,
                        ConstVar::$BALANCE_TYPE_USER,
                        ConstVar::$BALANCE_TYPE_USER
                    );
                    break;
                case ConstVar::$ORDER_TYPE_HONGBAO:
                    DB::rollBack();
                    return 'fail';
                    break;
                default:
                    return $this->sendFailResponse(400, 50001);
            }
            $this->order->sid = $balance_id;
            $this->order->status = 1;
            $this->order->buyer_channel_id = Auth::id();
            $this->order->buyer_channel_account = Auth::id();
            $this->order->receipt_amount = $real_amount;
            $this->order->save();
        }catch (\Exception $e){
            DB::rollBack();
            return $this->sendFailResponse(500, 50000, $e->getMessage());
        }
        DB::commit();
        return $this->sendSuccessResponse([]);
    }

    /**
     * 余额流水
     * @param $id
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function balances($id, Request $request){
        $valid_data = $request->all();
        $valid_data['id'] = $id;
        $validator = Validator::make($valid_data, [
            'id' => 'required|integer',
            'page' => 'required|integer',
            'size' => 'required|integer',
            'start_at' => 'required|integer',
            'end_at' => 'required|integer',
            'type' => 'required|in:1,2',//1-用户 2-商家
        ], [
            'id.required' => '10001',
            'id.integer' => '10002',
            'page.required' => '10001',
            'page.integer' => '10002',
            'size.required' => '10001',
            'size.integer' => '10002',
            'type.required' => '10001',
            'type.in' => '10002',
            'start_at.integer' => '10002',
            'end_at.integer' => '10002',
        ]);
        if ($validator->fails()) {
            return $this->sendFailResponse(400, $validator->errors()->first());
        }

        if(Auth::id() != $id && $request['type'] == 1){
            return $this->sendFailResponse(400, 40101);
        }

        if($request['type'] == 2){
            if(!CheckAuth::checkIfManager($id)){
                return $this->sendFailResponse(400, 40101);
            }
        }

        $this->balance->addDecorator(new IsEndDecorator());
        $this->balance->addDecorator(new BalanceDecorator($id, $request['type']));

        $data = $this->balance->getBalances(
            $id,
            $request['page'],
            $request['size'],
            $request['type'],
            $request['start_at'],
            $request['end_at']
        );
        if($request['type'] == 1){
            $data['income'] = [];
            $data['outlay'] = [];
            if(isset($data['list'][0])){
                $end = end($data['list']);
                $start_time = strtotime(date('Y-m-d', $end['created_at']));
                $end_time = strtotime(date('Y-m-d 23:59:59', $data['list'][0]['created_at']));
                $data['income'] = $this->balance->selectRaw("DATE_FORMAT(FROM_UNIXTIME(created_at), '%Y-%m') as date, sum(balance) as balance")
                    ->where('to_id', $id)
                    ->where('to_type', $request['type'])->where('status', 1)
                    ->whereBetween('created_at', [$start_time, $end_time])
                    ->groupBy(DB::raw("DATE_FORMAT(FROM_UNIXTIME(created_at), '%Y-%m')"))
                    ->get();
                $data['outlay'] = $this->balance->selectRaw("DATE_FORMAT(FROM_UNIXTIME(created_at), '%Y-%m') as date, sum(balance) as balance")
                    ->where('from_id', $id)
                    ->where('from_type', $request['type'])
                    ->whereBetween('created_at', [$start_time, $end_time])
                    ->groupBy(DB::raw("DATE_FORMAT(FROM_UNIXTIME(created_at), '%Y-%m')"))
                    ->get();
            }
        }else{
            $data['total_income'] = Shop::where('shop_id', $id)->first()->balance;
            $data['income'] = [];
            if(isset($data['list'][0])){
                $end = end($data['list']);
                $start_time = strtotime(date('Y-m-d', $end['created_at']));
                $end_time = strtotime(date('Y-m-d 23:59:59', $data['list'][0]['created_at']));
                $data['income'] = $this->balance->selectRaw("DATE_FORMAT(FROM_UNIXTIME(created_at), '%Y-%m-%d') as date, sum(balance) as balance")
                    ->where('to_id', $id)
                    ->where('to_type', $request['type'])->where('status', 1)
                    ->whereBetween('created_at', [$start_time, $end_time])
                    ->groupBy(DB::raw("DATE_FORMAT(FROM_UNIXTIME(created_at), '%Y-%m-%d')"))
                    ->get();
            }
        }

        return $this->sendSuccessResponse($data);
    }

    /**
     * 退款
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function refund(Request $request){
        $validator = Validator::make($request->all(), [
            'id' => 'required|integer',
            'type' => 'required|in:1,2,3,4,5,6',//1-post 2-product 3-transfer_to_shop 4-coupon 5-transfer_to_user 6-hongbao
        ], [
            'id.required' => '10001',
            'id.integer' => '10002',
            'type.required' => '10001',
            'type.in' => '10002',
        ]);

        if ($validator->fails()) {
            return $this->sendFailResponse(400, $validator->errors()->first());
        }

        switch($request['type']){//1-post 2-product 3-transfer 4-coupon
            case 1:
                return $this->sendFailResponse(400, 50001);
            case 2:
                return $this->sendFailResponse(400, 50001);
            case 3:
                //todo
                return $this->sendFailResponse(400, 50001);
            case 4:
                $shopCouponPurchase = $this->shopCouponPurchase->where('id', $request['id'])->first();
                if(empty($shopCouponPurchase) || empty($shopCouponPurchase->order_id)){
                    return $this->sendFailResponse(400, 40400);
                }
                if($shopCouponPurchase->status != ConstVar::$PURCHASE_STATUS_UNUSED){
                    return $this->sendFailResponse(400, 40001);
                }

                $order = $this->order->where('id', $shopCouponPurchase->order_id)->first();
                if(empty($order)){
                    return $this->sendFailResponse(400, 40400);
                }
                if($order->status != ConstVar::$ORDER_STATUS_SUCCESS){
                    return $this->sendFailResponse(400, 40001);
                }
                if($order->user_id != Auth::id() || $shopCouponPurchase->user_id != Auth::id()){
                    return $this->sendFailResponse(400, 40001);
                }
                $shopCouponPurchase->status = ConstVar::$PURCHASE_STATUS_REFUNDED;
                $order->status = ConstVar::$ORDER_STATUS_REFUNDED;
                $shopCouponPurchase->save();
                $order->save();
                $this->user->where('user_id', Auth::id())->increment('balance', $shopCouponPurchase->amount);
                $this->balance->where('purchase_id', $shopCouponPurchase->id)
                    ->where('from_id', $shopCouponPurchase->user_id)->update(['status'=>2]);
                $this->balance->add(//消费记录
                    Msg::system_refund().'_'.Msg::system_refund(),
                    0,//from_id
                    $shopCouponPurchase->user_id,
                    ConstVar::$BALANCE_CHANNEL_BALANCE,
                    ConstVar::$BALANCE_CHANNEL_BALANCE,
                    ConstVar::$ORDER_TYPE_COUPON,
                    $shopCouponPurchase->coupon_id,//coupon_id
                    $order->receipt_amount,
                    $shopCouponPurchase->id,
                    $order->hong_bao_id,
                    $order->hong_bao_amount,
                    ConstVar::$BALANCE_STATUS_SUCCESS,
                    ConstVar::$BALANCE_TYPE_SYSTEM,
                    ConstVar::$BALANCE_TYPE_USER,
                    ConstVar::$BALANCE_REFUND
                );
                break;
            default:
                return $this->sendFailResponse(400, 50001);
        }
        dispatch(new SendSystemMsgJob([$shopCouponPurchase->user_id], Msg::refund_success(), 0));
        return $this->sendSuccessResponse([]);
    }
}